﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAudio.Wave;

namespace ShapeGame
{
    class ThereminSound
    {
        WaveOut waveOut;
        float oldPitch, newPitch;

        SquareWaveProvider32 squareWaveProvider;
        SineWaveProvider32 sineWaveProvider;

        public void StartStopSquareWave()
        {
            if (waveOut == null)
            {
                squareWaveProvider = new SquareWaveProvider32();
                squareWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
                squareWaveProvider.Frequency = 125;
                squareWaveProvider.Amplitude = 0.25f;
                waveOut = new WaveOut();
                waveOut.Init(squareWaveProvider);
                waveOut.DesiredLatency = 10;
                waveOut.Play();
            }
            else
            {
                waveOut.Stop();
                waveOut.Dispose();
                waveOut = null;
                squareWaveProvider = null;
            }
        }

        public void StartStopSineWave()
        {
            if (waveOut == null)
            {
                var sineWaveProvider = new SineWaveProvider32();
                sineWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
                sineWaveProvider.Frequency = 1000;
                sineWaveProvider.Amplitude = 0.25f;
                waveOut = new WaveOut();
                waveOut.Init(sineWaveProvider);
                waveOut.Play();
            }
            else
            {
                waveOut.Stop();
                waveOut.Dispose();
                waveOut = null;
                sineWaveProvider = null;
            }
        }

        public void setPitch(float pitch)
        {
            newPitch = (oldPitch + pitch)/2;
            oldPitch = pitch;

            if (squareWaveProvider != null)
            {
                squareWaveProvider.setFrequency(newPitch); 
            }
            if (sineWaveProvider != null)
            {
                sineWaveProvider.setFrequency(newPitch);
            }
        }

        public void setVolume(float volume)
        {
            if (squareWaveProvider != null)
            {
                squareWaveProvider.setAmplitude(volume); 
            }
            if (sineWaveProvider != null)
            {
                sineWaveProvider.setAmplitude(volume);
            }
        }

    }

    public class SquareWaveProvider32 : WaveProvider32
    {
        int sample;

        public SquareWaveProvider32()
        {
            Frequency = 440;
            Amplitude = 0.25f; // let's not hurt our ears            
        }

        public float Frequency { get; set; }
        public float Amplitude { get; set; }

        public void setFrequency(float frequency)
        {
            this.Frequency = frequency;
        }

        public void setAmplitude(float amplitude)
        {
            this.Amplitude = amplitude;
        }

        public override int Read(float[] buffer, int offset, int sampleCount)
        {
            int sampleRate = WaveFormat.SampleRate;
            int Channels = WaveFormat.Channels;
            double phaseAngle;
            phaseAngle = ((Math.PI * 2 * Frequency) / (sampleRate * Channels));


            for (int n = 0; n < sampleCount; n++)
            {
                if (Math.Sign(Math.Sin(phaseAngle * sample)) > 0)
                    buffer[n + offset] = Amplitude;
                else
                    buffer[n + offset] = -Amplitude;

                sample++;
                if (sample >= sampleRate) sample = 0;
            }
            return sampleCount;
        }
    }

    public class SineWaveProvider32 : WaveProvider32
    {
        int sample;

        public SineWaveProvider32()
        {
            Frequency = 1000;
            Amplitude = 0.25f; // let's not hurt our ears            
        }

        public float Frequency { get; set; }
        public float Amplitude { get; set; }


        public void setFrequency(double frequency)
        {
            this.Frequency = (float)frequency;
        }

        public void setAmplitude(double amplitude)
        {
            this.Amplitude = (float)amplitude;
        }

        public override int Read(float[] buffer, int offset, int sampleCount)
        {
            int sampleRate = WaveFormat.SampleRate;
            for (int n = 0; n < sampleCount; n++)
            {
                buffer[n + offset] = (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate));
                sample++;
                if (sample >= sampleRate) sample = 0;
            }
            return sampleCount;
        }
    } 
}

    

